using System.Collections.Generic;
using Opc.Ua;
using Opc.Ua.Client;

namespace HslCommunicationEx.OpcUa
{
	public class FilterDefinition
	{
		public NodeId AreaId;

		public EventSeverity Severity;

		public IList<NodeId> EventTypes;

		public bool IgnoreSuppressedOrShelved;

		public SimpleAttributeOperandCollection SelectClauses;

		public MonitoredItem CreateMonitoredItem(Session session)
		{
			if (this.AreaId == null)
			{
				this.AreaId = ObjectIds.Server;
			}
			MonitoredItem monitoredItem = new MonitoredItem();
			monitoredItem.DisplayName = null;
			monitoredItem.StartNodeId = this.AreaId;
			monitoredItem.RelativePath = null;
			monitoredItem.NodeClass = NodeClass.Object;
			monitoredItem.AttributeId = 12u;
			monitoredItem.IndexRange = null;
			monitoredItem.Encoding = null;
			monitoredItem.MonitoringMode = MonitoringMode.Reporting;
			monitoredItem.SamplingInterval = 0;
			monitoredItem.QueueSize = uint.MaxValue;
			monitoredItem.DiscardOldest = true;
			monitoredItem.Filter = this.ConstructFilter(session);
			monitoredItem.Handle = this;
			return monitoredItem;
		}

		public SimpleAttributeOperandCollection ConstructSelectClauses(Session session, params NodeId[] eventTypeIds)
		{
			SimpleAttributeOperandCollection simpleAttributeOperandCollection = new SimpleAttributeOperandCollection();
			SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand();
			simpleAttributeOperand.TypeDefinitionId = ObjectTypeIds.BaseEventType;
			simpleAttributeOperand.AttributeId = 1u;
			simpleAttributeOperand.BrowsePath = new QualifiedNameCollection();
			simpleAttributeOperandCollection.Add(simpleAttributeOperand);
			if (eventTypeIds != null)
			{
				for (int i = 0; i < eventTypeIds.Length; i++)
				{
					this.CollectFields(session, eventTypeIds[i], simpleAttributeOperandCollection);
				}
			}
			else
			{
				this.CollectFields(session, ObjectTypeIds.BaseEventType, simpleAttributeOperandCollection);
			}
			return simpleAttributeOperandCollection;
		}

		public EventFilter ConstructFilter(Session session)
		{
			EventFilter eventFilter = new EventFilter();
			eventFilter.SelectClauses = this.SelectClauses;
			ContentFilter contentFilter = new ContentFilter();
			ContentFilterElement contentFilterElement = null;
			ContentFilterElement contentFilterElement2 = null;
			if (this.Severity > EventSeverity.Min)
			{
				SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand();
				simpleAttributeOperand.TypeDefinitionId = ObjectTypeIds.BaseEventType;
				simpleAttributeOperand.BrowsePath.Add("Severity");
				simpleAttributeOperand.AttributeId = 13u;
				LiteralOperand literalOperand = new LiteralOperand();
				literalOperand.Value = new Variant((ushort)this.Severity);
				contentFilterElement = contentFilter.Push(FilterOperator.GreaterThanOrEqual, simpleAttributeOperand, literalOperand);
			}
			if (!this.IgnoreSuppressedOrShelved)
			{
				SimpleAttributeOperand simpleAttributeOperand2 = new SimpleAttributeOperand();
				simpleAttributeOperand2.TypeDefinitionId = ObjectTypeIds.BaseEventType;
				simpleAttributeOperand2.BrowsePath.Add("SuppressedOrShelved");
				simpleAttributeOperand2.AttributeId = 13u;
				LiteralOperand literalOperand2 = new LiteralOperand();
				literalOperand2.Value = new Variant(value: false);
				contentFilterElement2 = contentFilter.Push(FilterOperator.Equals, simpleAttributeOperand2, literalOperand2);
				contentFilterElement = ((contentFilterElement == null) ? contentFilterElement2 : contentFilter.Push(FilterOperator.And, contentFilterElement, contentFilterElement2));
			}
			if (this.EventTypes != null && this.EventTypes.Count > 0)
			{
				contentFilterElement2 = null;
				for (int i = 0; i < this.EventTypes.Count; i++)
				{
					LiteralOperand literalOperand3 = new LiteralOperand();
					literalOperand3.Value = new Variant(this.EventTypes[i]);
					ContentFilterElement contentFilterElement3 = contentFilter.Push(FilterOperator.OfType, literalOperand3);
					contentFilterElement2 = ((contentFilterElement2 == null) ? contentFilterElement3 : contentFilter.Push(FilterOperator.Or, contentFilterElement2, contentFilterElement3));
				}
				if (contentFilterElement != null)
				{
					contentFilter.Push(FilterOperator.And, contentFilterElement, contentFilterElement2);
				}
			}
			eventFilter.WhereClause = contentFilter;
			return eventFilter;
		}

		private void CollectFields(Session session, NodeId eventTypeId, SimpleAttributeOperandCollection eventFields)
		{
			ReferenceDescriptionCollection referenceDescriptionCollection = FormUtils.BrowseSuperTypes(session, eventTypeId, throwOnError: false);
			if (referenceDescriptionCollection != null)
			{
				Dictionary<NodeId, QualifiedNameCollection> foundNodes = new Dictionary<NodeId, QualifiedNameCollection>();
				QualifiedNameCollection parentPath = new QualifiedNameCollection();
				for (int num = referenceDescriptionCollection.Count - 1; num >= 0; num--)
				{
					this.CollectFields(session, (NodeId)referenceDescriptionCollection[num].NodeId, parentPath, eventFields, foundNodes);
				}
				this.CollectFields(session, eventTypeId, parentPath, eventFields, foundNodes);
			}
		}

		private void CollectFields(Session session, NodeId nodeId, QualifiedNameCollection parentPath, SimpleAttributeOperandCollection eventFields, Dictionary<NodeId, QualifiedNameCollection> foundNodes)
		{
			BrowseDescription browseDescription = new BrowseDescription();
			browseDescription.NodeId = nodeId;
			browseDescription.BrowseDirection = BrowseDirection.Forward;
			browseDescription.ReferenceTypeId = ReferenceTypeIds.Aggregates;
			browseDescription.IncludeSubtypes = true;
			browseDescription.NodeClassMask = 3u;
			browseDescription.ResultMask = 63u;
			ReferenceDescriptionCollection referenceDescriptionCollection = FormUtils.Browse(session, browseDescription, throwOnError: false);
			if (referenceDescriptionCollection == null)
			{
				return;
			}
			for (int i = 0; i < referenceDescriptionCollection.Count; i++)
			{
				ReferenceDescription referenceDescription = referenceDescriptionCollection[i];
				if (!referenceDescription.NodeId.IsAbsolute)
				{
					QualifiedNameCollection qualifiedNameCollection = new QualifiedNameCollection(parentPath);
					qualifiedNameCollection.Add(referenceDescription.BrowseName);
					if (!this.ContainsPath(eventFields, qualifiedNameCollection))
					{
						SimpleAttributeOperand simpleAttributeOperand = new SimpleAttributeOperand();
						simpleAttributeOperand.TypeDefinitionId = ObjectTypeIds.BaseEventType;
						simpleAttributeOperand.BrowsePath = qualifiedNameCollection;
						simpleAttributeOperand.AttributeId = ((referenceDescription.NodeClass != NodeClass.Variable) ? 1u : 13u);
						eventFields.Add(simpleAttributeOperand);
					}
					NodeId key = (NodeId)referenceDescription.NodeId;
					if (!foundNodes.ContainsKey(key))
					{
						foundNodes.Add(key, qualifiedNameCollection);
						this.CollectFields(session, (NodeId)referenceDescription.NodeId, qualifiedNameCollection, eventFields, foundNodes);
					}
				}
			}
		}

		private bool ContainsPath(SimpleAttributeOperandCollection selectClause, QualifiedNameCollection browsePath)
		{
			for (int i = 0; i < selectClause.Count; i++)
			{
				SimpleAttributeOperand simpleAttributeOperand = selectClause[i];
				if (simpleAttributeOperand.BrowsePath.Count != browsePath.Count)
				{
					continue;
				}
				bool flag = true;
				for (int j = 0; j < simpleAttributeOperand.BrowsePath.Count; j++)
				{
					if (simpleAttributeOperand.BrowsePath[j] != browsePath[j])
					{
						flag = false;
						break;
					}
				}
				if (flag)
				{
					return true;
				}
			}
			return false;
		}
	}
}
